﻿#include"源.h"

//位段 - 位：二进制位 - 专门用来减少内存
//位段的声明和结构是类似的，有两个不同：
//1. 位段的成员必须是 int、unsigned int 或signed int ，在C99中位段成员的类型也可以
//选择其他类型。
//2. 位段的成员名后边有⼀个冒号和⼀个数字。
// 
//位段的内存分配：
//1. 位段的成员可以是 int unsigned int signed int 或者是 char 等类型
//2. 位段的空间上是按照需要以4个字节（ int ）或者1个字节（ char ）的⽅式来开辟的。
//3. 位段涉及很多不确定因素，位段是不跨平台的，注重可移植的程序应该避免使⽤位段。
//
//位段的跨平台问题：
//1. int 位段被当成有符号数还是⽆符号数是不确定的。
//2. 位段中最⼤位的数⽬不能确定。（16位机器最⼤16，32位机器最⼤32，写成27，在16位机器会出问题。
//3. 位段中的成员在内存中从左向右分配，还是从右向左分配，标准尚未定义。
//4. 当⼀个结构包含两个位段，第⼆个位段成员⽐较⼤，⽆法容纳于第⼀个位段剩余的位时，是舍弃
//剩余的位还是利⽤，这是不确定的。
//
//根据不同的平台写不同的代码
//
//位段的应⽤
//下图是⽹络协议中，IP数据报的格式，我们可以看到其中很多的属性只需要⼏个bit位就能描述，这⾥
//使⽤位段，能够实现想要的效果，也节省了空间，这样⽹络传输的数据报⼤⼩也会较⼩⼀些，对⽹络
//的畅通是有帮助的。
//
//位段使⽤的注意事项
//位段的⼏个成员共有同⼀个字节，这样有些成员的起始位置并不是某个字节的起始位置，那么这些位
//置处是没有地址的。内存中每个字节分配⼀个地址，⼀个字节内部的bit位是没有地址的。
//所以不能对位段的成员使⽤& 操作符，这样就不能使⽤scanf直接给位段的成员输⼊值，只能是先输⼊
//放在⼀个变量中，然后赋值给位段的成员。

//struct A
//{
//	int _a : 2;
//	int _b : 5;
//	int _c : 10;
//	int _d : 30;
//};
//
//int main()
//{
//	struct A sa = { 0 };
//	//scanf("%d", &sa._b);//这是错误的
//
//	//正确的⽰范
//	int b = 0;
//	scanf("%d", &b);
//	sa._b = b;
//	printf("%d\n", sa._b);
//	return 0;
//}


//struct S
//{
//	char a : 3;
//	char b : 4;
//	char c : 5;
//	char d : 4;
//};
//int main()
//{
//	struct S s = { 0 };
//	s.a = 10;
//	s.b = 12;
//	s.c = 3;
//	s.d = 4;
//
//	return 0;
//}


//struct A
//{
//	int _a : 2;//只占2个bit位
//	int _b : 5;//只占5个bit位
//	int _c : 10;//只占10个bit位
//	int _d : 30;//只占30个bit位
//};
//
//int main()
//{
//	printf("%zd\n", sizeof(struct A));
//	return 0;
//}


//struct S
//{
//	int arr[1000];
//	int n;
//	double d;
//};
//
////void Print1(struct S tmp)
////{
////	int i = 0;
////	for (i = 0; i < 5; i++)
////	{
////		printf("%d ", tmp.arr[i]);
////	}
////	printf("%d\n", tmp.n);
////	printf("%lf\n", tmp.d);
////}
//
//void Print2(const struct S* ps)
//{
//	assert(ps);
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		printf("%d ", ps->arr[i]);
//	}
//	printf("%d\n", ps->n);
//	printf("%lf\n", ps->d);
//}
//
//int main()
//{
//	struct S s1 = { {1,2,3,4,5},100,3.14 };
//	//Print1(s1);//结构体传参时，尽量传递地址
//	Print2(&s1);
//	return 0;
//}


//结构体的内存对齐
//结构体的对⻬规则：
//1. 结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
//2. 其他成员变量要对⻬到某个数字（对⻬数）的整数倍的地址处。
//   对⻬数 = 编译器默认的⼀个对⻬数 与 该成员变量⼤⼩的较⼩值。
//   - VS 中默认的值为 8
//   - Linux中 gcc 没有默认对⻬数，对⻬数就是成员⾃⾝的⼤⼩
//3.结构体总⼤⼩为最⼤对⻬数（结构体中每个成员变量都有⼀个对⻬数，所有对⻬数中最⼤的）的整数倍。
//4.如果嵌套了结构体的情况，嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处，
//  结构体的整体⼤⼩就是所有最⼤对⻬数（含嵌套结构体中成员的对⻬数）的整数倍

//#pragma pack(1)//设置默认对⻬数为1
//struct S
//{
//	char c1;
//	int i;
//	char c2;
//};
//#pragma pack()//取消设置的对⻬数，还原为默认
//
//int main()
//{
//	printf("%zd\n", sizeof(struct S));
//	return 0;
//}


//struct S
//{
//	char c1;
//	int i;
//	char c2;
//};
//struct S2
//{
//	char c1;
//	char c2;
//	int i;
//}; 
//struct S3
//{
//	double d;//8
//	char c;
//	int i;
//};
//struct S4
//{
//	char c1;
//	struct S3 s3;
//	double d;
//};
//int main()
//{
//	struct S s = { 0 };
//	struct S2 s2 = { 0 };
//	struct S3 s3 = { 0 };
//	struct S4 s4 = { 0 };
//	printf("%zd\n", sizeof(s));
//	printf("%zd\n", sizeof(s2));
//	printf("%zd\n", sizeof(s3));
//	printf("%zd\n", sizeof(s4));
//	return 0;
//}


//typedef struct Node//链表
//{
//	int date;//数据
//	struct Node* next;//指针
//}Node;

//struct Node//链表
//{
//	int date;//数据
//	struct Node* next;//指针
//};
//typedef struct Node Node;
//
//int main()
//{
//	struct Node n1;
//	Node n2;
//	return 0;
//}


//匿名结构体类型
//编译器会把上⾯的两个声明当成完全不同的两个类型，所以是⾮法的。
//匿名的结构体类型，如果没有对结构体类型重命名的话，基本上只能使⽤⼀次。
//匿名结构体无法实现结构体自引用
// 
//struct
//{
//	int a;
//	char b;
//	float c;
//}x = {9,'A',2.2};
//
//struct
//{
//	int a;
//	char b;
//	float c;
//}a[20], * p;
//
//int main()
//{
//	printf("%d,%c,%.2f\n", x.a, x.b, x.c);
//	return 0;
//}


//结构体的声明
//struct tag
//{
//	member - list;
//}variable - list;

//struct Stu
//{
//	char name[20];//名字
//	int age;//年龄
//	char sex[5];//性别
//	char id[20];//学号
//}s3,s4; //全局变量
//
//struct Stu s3;//全局变量
//
//int main()
//{
//
//	//按照结构体成员的顺序初始化
//	struct Stu s1 = { "张三", 20, "男", "20230818001" };
//	printf("name: %s\n", s1.name);
//	printf("age : %d\n", s1.age);
//	printf("sex : %s\n", s1.sex);
//	printf("id : %s\n", s1.id);
//
//	//按照指定的顺序初始化
//	struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex ="⼥" };
//	printf("name: %s\n", s2.name);
//	printf("age : %d\n", s2.age);
//	printf("sex : %s\n", s2.sex);
//	printf("id : %s\n", s2.id);
//
//	return 0;
//}